package com.basic.backend.service.impl;

import com.basic.backend.config.RabbitMQConfig;
import com.basic.backend.model.dto.Images.ImageAnalysisDTO;
import com.basic.backend.model.dto.analysis.AnalysisResponse;
import com.basic.backend.model.entity.AnalysisResult;
import com.basic.backend.service.AnalysisService;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.rabbitmq.client.Channel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.*;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@RequiredArgsConstructor
public class ImageAnalysisConsumer {

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private AnalysisService analysisService;

    @Resource
    private RedisTemplate<String, Integer> redisTemplate;

    @Value("${analysis.service.url1}")
    private String analysisServiceUrl;

    @Value("${retry.max-attempts:3}")
    private int maxRetries;

    @Value("${retry.initial-delay:5000}")
    private long initialDelay;

    @Resource
    private AnalysisResultService resultService;

    // 消息处理入口
    @RabbitListener(queues = RabbitMQConfig.IMAGE_QUEUE)
    public void processAnalysisTask(
            ImageAnalysisDTO dto,
            Message message,
            @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag,
            Channel channel) {

        final String redisKey = String.format("retry:image:%d", dto.getArticleId());
        log.info("Received message: articleId={}", dto.getArticleId());

        try {
            handleMessageProcessing(dto, deliveryTag, channel, redisKey);
        } catch (Exception e) {
            log.error("Message processing failed: articleId={}", dto.getArticleId(), e);
            handleProcessingError(dto.getArticleId(), deliveryTag, channel, redisKey, e);
        }
    }

    private void handleMessageProcessing(ImageAnalysisDTO dto, long deliveryTag,
                                         Channel channel, String redisKey)
            throws Exception {

        int retryCount = Optional.ofNullable(redisTemplate.opsForValue().get(redisKey))
                .orElse(0);

        if (retryCount >= maxRetries) {
            handleMaxRetries(dto.getArticleId(), deliveryTag, channel, redisKey);
            return;
        }

        AnalysisResponse result = processAnalysis(dto);
        resultService.saveResult(dto.getArticleId(), result);
        acknowledgeMessage(deliveryTag, channel, redisKey);
    }

    // 业务处理核心方法
    private AnalysisResponse processAnalysis(ImageAnalysisDTO dto) {
        try {
            log.info("Calling analysis service for article: {}", dto.getArticleId());
            HttpEntity<Map<String, Object>> requestEntity = buildRequestEntity(dto);
            log.info("Request payload: {}", requestEntity.getBody());
            ResponseEntity<AnalysisResponse> response = restTemplate.exchange(
                    analysisServiceUrl,
                    HttpMethod.POST,
                    requestEntity,
                    AnalysisResponse.class
            );

            log.info("Analysis result received: {}", response.getBody());
            return response.getBody();
        } catch (RestClientException e) {
            log.error("API call failed: {}", e.getMessage());
            throw new RuntimeException("Analysis service unavailable", e);
        }
    }

    // 构建请求实体
    private HttpEntity<Map<String, Object>> buildRequestEntity(ImageAnalysisDTO dto) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("X-Request-ID", String.valueOf(dto.getArticleId()));

        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("images", dto.getImageUrls());
        requestBody.put("content", dto.getContent());
        requestBody.put("title", dto.getTitle());
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        requestBody.put("publishTime",
                LocalDateTime.now().format(formatter).toString());

        log.debug("Request payload: {}", requestBody);
        return new HttpEntity<>(requestBody, headers);
    }

    // 响应验证
    private void validateResponse(ResponseEntity<AnalysisResult> response) {
        if (response.getStatusCode() != HttpStatus.OK || response.getBody() == null) {
            throw new RuntimeException("Invalid service response: " + response.getStatusCode());
        }

        AnalysisResult result = response.getBody();
    }

    // 持久化结果
    private void saveAnalysisResult(AnalysisResult result) {
        try {
            analysisService.save(result);
            log.info("Analysis result saved: articleId={}", result.getArticleId());
        } catch (Exception e) {
            log.error("Failed to save analysis result: {}", result, e);
            throw new RuntimeException("Persistence failure", e);
        }
    }

    // 消息确认
    private void acknowledgeMessage(long deliveryTag, Channel channel, String redisKey)
            throws IOException {

        channel.basicAck(deliveryTag, false);
        redisTemplate.delete(redisKey);
        log.debug("Message acknowledged: deliveryTag={}", deliveryTag);
    }

    // 重试上限处理
    private void handleMaxRetries(Long articleId, long deliveryTag,
                                  Channel channel, String redisKey)
            throws IOException {

        log.warn("Message moved to DLQ: articleId={}", articleId);
        channel.basicReject(deliveryTag, false);
        redisTemplate.delete(redisKey);
    }

    // 异常处理增强
    private void handleProcessingError(Long articleId, long deliveryTag,
                                       Channel channel, String redisKey,
                                       Exception exception) {

        try {
            handleRetryLogic(articleId, deliveryTag, channel, redisKey);
        } catch (Exception e) {
            log.error("Critical error handling failure: articleId={}", articleId, e);
            safelyReleaseMessage(deliveryTag, channel);
        }
    }

    // 重试逻辑优化
    private void handleRetryLogic(Long articleId, long deliveryTag,
                                  Channel channel, String redisKey)
            throws IOException {

        Long newCount = redisTemplate.opsForValue().increment(redisKey, 1L);
        redisTemplate.expire(redisKey, Duration.ofHours(24));

        if (newCount >= maxRetries) {
            log.warn("Final retry failed: articleId={}", articleId);
            channel.basicReject(deliveryTag, false);
        } else {
            long delay = calculateBackoffDelay(newCount);
            log.info("Scheduling retry: articleId={}, attempt={}, delay={}ms",
                    articleId, newCount, delay);

            channel.basicNack(deliveryTag, false, false);
        }
    }

    // 指数退避计算
    private long calculateBackoffDelay(Long retryCount) {
        return (long) (initialDelay * Math.pow(2, retryCount - 1));
    }

    // 安全释放消息
    private void safelyReleaseMessage(long deliveryTag, Channel channel) {
        try {
            channel.basicNack(deliveryTag, false, false);
        } catch (IOException e) {
            log.error("Critical message handling failure", e);
        }
    }


}